
package com.hlkj.pay.gateway.order.impl;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.hlkj.framework.common.pojo.CommonResult;
import com.hlkj.framework.extension.executor.ExtensionExecutor;
import com.hlkj.framework.extension.scenario.BizScenario;
import com.hlkj.pay.app.merchant.ext.ChannelMerchantAccessExtPt;
import com.hlkj.pay.app.merchant.ext.ChannelMerchantOrderExtPt;
import com.hlkj.pay.app.merchant.ext.MerchantExtConstant;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelRefundPayOrderContext;
import com.hlkj.pay.dto.order.RefundOrderChannelResultDto;
import com.hlkj.pay.dto.order.notify.RefundOrderNotifyDto;
import com.hlkj.pay.enums.PayEnums;
import com.hlkj.pay.enums.PayOrderEnums;
import com.hlkj.pay.gateway.order.IChannelRefundOrderGateway;
import com.hlkj.pay.infrastructure.model.merchant.MerchantAppChannelDO;
import com.hlkj.pay.infrastructure.model.order.PayOrderDO;
import com.hlkj.pay.infrastructure.model.order.RefundOrderDO;
import com.hlkj.pay.infrastructure.model.pay.PayChannelRequestDO;
import com.hlkj.pay.infrastructure.model.pay.ProviderChannelConfigDO;
import com.hlkj.pay.service.merchant.IMerchantApplicationService;
import com.hlkj.pay.service.order.IPayOrderService;
import com.hlkj.pay.service.pay.IPayChannelService;
import com.hlkj.pay.service.pay.IPayWayService;
import com.hlkj.pay.service.pay.IProviderService;

import jodd.util.StringPool;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author HlpayTeam
 * @date 2024/11/06 14:18
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ChannelRefundOrderGatewayImpl implements IChannelRefundOrderGateway {

    @Value("${hlkj.pay.barrier:false}")
    private boolean barrier;

    @Value("${hlkj.pay.test:false}")
    private boolean test;

    @Value("${hlkj.domain}")
    private String domain;

    private final ExtensionExecutor extensionExecutor;

    private final IMerchantApplicationService merchantApplicationService;

    private final IPayWayService payWayService;

    private final IProviderService providerService;

    private final IPayChannelService payChannelService;
    private final IPayOrderService payOrderService;

    @Override
    public boolean refundApply(PayOrderDO payOrderDO) {
        if (barrier) {
            log.info("测试环境支持退款成功 payOrderNo:{}", payOrderDO.getPayOrderNo());
            RefundOrderChannelResultDto refundOrderChannelResultDto = new RefundOrderChannelResultDto();
            refundOrderChannelResultDto.setUpdateRefundOrderDO(null);
            return true;
        }
        MerchantAppChannelDO merchantAppChannelDO = merchantApplicationService.queryAppChannelDetail(payOrderDO.getMchChannelCode());
        ChannelRefundPayOrderContext channelRefundPayOrderContext = new ChannelRefundPayOrderContext();
        channelRefundPayOrderContext.setMerchantAppChannelDO(merchantAppChannelDO);
        channelRefundPayOrderContext.setPayOrderDO(payOrderDO);
        channelRefundPayOrderContext.setPayWayDO(payWayService.queryByCode(payOrderDO.getPayWayCode()));
        channelRefundPayOrderContext.setTest(test);
        return extensionExecutor.execute(ChannelMerchantOrderExtPt.class, BizScenario.valueOf(merchantAppChannelDO.getChannelCode()),
                ex -> ex.refundApply(channelRefundPayOrderContext));
    }

    @Override
    public RefundOrderChannelResultDto submitChannelRefundOrder(PayOrderDO payOrderDO, RefundOrderDO refundOrderDO) {
        if (barrier) {
            log.info("测试环境退款直接返回成功 payOrderNo:{}", payOrderDO.getPayOrderNo());
            RefundOrderChannelResultDto refundOrderChannelResultDto = new RefundOrderChannelResultDto();
            refundOrderChannelResultDto.setUpdateRefundOrderDO(null);
            return refundOrderChannelResultDto;
        }
        MerchantAppChannelDO merchantAppChannelDO = merchantApplicationService.queryAppChannelDetail(payOrderDO.getMchChannelCode());
        ChannelRefundPayOrderContext channelRefundPayOrderContext = new ChannelRefundPayOrderContext();
        channelRefundPayOrderContext.setMerchantAppChannelDO(merchantAppChannelDO);
        channelRefundPayOrderContext.setPayOrderDO(payOrderDO);
        channelRefundPayOrderContext.setRefundOrderDO(refundOrderDO);
        channelRefundPayOrderContext.setPayWayDO(payWayService.queryByCode(payOrderDO.getPayWayCode()));
        channelRefundPayOrderContext.setProviderChannelConfigDO(providerService.queryConfig(merchantAppChannelDO.getProviderCode(), merchantAppChannelDO.getChannelCode()));
        channelRefundPayOrderContext
                .setNotifyUrl(domain + MerchantExtConstant.MERCHANT_REFUND_ASYNC_CALLBACK_URL + payOrderDO.getChannelCode() + StringPool.SLASH + payOrderDO.getProviderCode());
        channelRefundPayOrderContext.setTest(test);
        extensionExecutor.executeVoid(ChannelMerchantOrderExtPt.class, BizScenario.valueOf(merchantAppChannelDO.getChannelCode()),
                ex -> ex.refundChannelPayOrder(channelRefundPayOrderContext));

        PayChannelRequestDO payChannelRequestDO = channelRefundPayOrderContext.getPayChannelRequestDO();
        if (payChannelRequestDO != null) {
            payChannelRequestDO.setRelationId(refundOrderDO.getRefundOrderNo());
            payChannelRequestDO.setSn(refundOrderDO.getSn());
            payChannelRequestDO.setProviderCode(refundOrderDO.getProviderCode());
            payChannelRequestDO.setChannelCode(refundOrderDO.getChannelCode());
            payChannelRequestDO.setMchChannelCode(refundOrderDO.getMchChannelCode());
            payChannelService.saveRequest(payChannelRequestDO, PayEnums.CHANNEL_REQUEST_TYPE.PAY_ORDER);
        }
        RefundOrderChannelResultDto refundOrderChannelResultDto = new RefundOrderChannelResultDto();
        refundOrderChannelResultDto.setProcessStatus(channelRefundPayOrderContext.isProcessStatus());
        refundOrderChannelResultDto.setRemark(channelRefundPayOrderContext.getRemark());
        refundOrderChannelResultDto.setUpdateRefundOrderDO(channelRefundPayOrderContext.getUpdateRefundOrderDO());
        return refundOrderChannelResultDto;
    }

    @Override
    public RefundOrderChannelResultDto queryChannelRefundOrder(RefundOrderDO refundOrderDO) {
        if (barrier) {
            log.info("测试环境退款直接返回成功 refundOrderNo:{}", refundOrderDO.getRefundOrderNo());
            RefundOrderChannelResultDto refundOrderChannelResultDto = new RefundOrderChannelResultDto();
            RefundOrderDO updateRefundOrderDO = new RefundOrderDO();
            updateRefundOrderDO.setRefundStatus(PayOrderEnums.REFUND_STATUS.REFUND.getCode());
            updateRefundOrderDO.setSuccessTime(System.currentTimeMillis());
            refundOrderChannelResultDto.setUpdateRefundOrderDO(updateRefundOrderDO);
            return refundOrderChannelResultDto;
        }
        MerchantAppChannelDO merchantAppChannelDO = merchantApplicationService.queryAppChannelDetail(refundOrderDO.getMchChannelCode());
        ChannelRefundPayOrderContext channelRefundPayOrderContext = new ChannelRefundPayOrderContext();
        channelRefundPayOrderContext.setMerchantAppChannelDO(merchantAppChannelDO);
        channelRefundPayOrderContext.setRefundOrderDO(refundOrderDO);
        channelRefundPayOrderContext.setPayOrderDO(payOrderService.queryPayOrder(refundOrderDO.getPayOrderNo()));
        channelRefundPayOrderContext.setPayWayDO(payWayService.queryByCode(refundOrderDO.getPayWayCode()));
        channelRefundPayOrderContext.setProviderChannelConfigDO(providerService.queryConfig(merchantAppChannelDO.getProviderCode(), merchantAppChannelDO.getChannelCode()));
        channelRefundPayOrderContext.setTest(test);
        extensionExecutor.executeVoid(ChannelMerchantOrderExtPt.class, BizScenario.valueOf(merchantAppChannelDO.getChannelCode()),
                ex -> ex.queryRefundChannelPayOrder(channelRefundPayOrderContext));
        RefundOrderChannelResultDto refundOrderChannelResultDto = new RefundOrderChannelResultDto();
        refundOrderChannelResultDto.setProcessStatus(channelRefundPayOrderContext.isProcessStatus());
        refundOrderChannelResultDto.setRemark(channelRefundPayOrderContext.getRemark());
        refundOrderChannelResultDto.setUpdateRefundOrderDO(channelRefundPayOrderContext.getUpdateRefundOrderDO());
        return refundOrderChannelResultDto;
    }

    @Override
    public CommonResult<RefundOrderNotifyDto> refundStatusParse(HttpServletRequest accessCallBody, ProviderChannelConfigDO providerChannelConfigDO) {
        return extensionExecutor.execute(ChannelMerchantOrderExtPt.class, BizScenario.valueOf(providerChannelConfigDO.getChannelCode()),
                ex -> ex.refundStatusParse(accessCallBody, providerChannelConfigDO));
    }

    @Override
    public String callBackResponse(String channelCode, CommonResult commonResult) {
        return extensionExecutor.execute(ChannelMerchantAccessExtPt.class, BizScenario.valueOf(channelCode), ex -> ex.callBackResponse(commonResult));
    }

    @Override
    public boolean extensionExist(String channelCode) {
        return extensionExecutor.executeExist(ChannelMerchantOrderExtPt.class, BizScenario.valueOf(channelCode));
    }
}
